import os, cgi, logging, time
import simplejson as json

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
from google.appengine.ext.webapp import template

import datetime

class Greeting(db.Model):
    author = db.UserProperty()
    content = db.StringProperty(multiline=True)
    date = db.DateTimeProperty(auto_now_add=True)

class LastReading(db.Model):
    author = db.UserProperty()
    content = db.StringProperty(multiline=True)
    mac = db.StringProperty()
    date = db.DateTimeProperty(auto_now_add=True)

class Reading(db.Model):
    mac = db.StringProperty()
    variable = db.StringProperty()
    timestamp = db.DateTimeProperty()
    timespan = db.StringProperty(choices=set(['r','m','h','day','week','mon','year'])) # r: raw; m: minute
    value = db.FloatProperty()

class Command(db.Model):
    mac = db.StringProperty()
    command = db.TextProperty()
    date = db.DateTimeProperty(auto_now_add=True)
    response = db.TextProperty()
    complete = db.BooleanProperty()

class User(db.Model):
    email = db.StringProperty()
    
class Device(db.Model):
    mac = db.StringProperty()
    description = db.StringProperty()
    
class MainPage(webapp.RequestHandler):
    def get(self):
        logging.info('Start of MainPage.get')
        greetings_query = Greeting.all().order('-date')
        greetings = greetings_query.fetch(10)

        if users.get_current_user():
            url = users.create_logout_url(self.request.uri)
            url_linktext = 'Logout'
        else:
            url = users.create_login_url(self.request.uri)
            url_linktext = 'Login'

        template_values = {
            'greetings': greetings,
            'url': url,
            'url_linktext': url_linktext,
            }

        path = os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(path, template_values))

class Guestbook(webapp.RequestHandler):
    def post(self):
        greeting = Greeting()

        if users.get_current_user():
            greeting.author = users.get_current_user()

        greeting.content = self.request.get('content')
        greeting.put()
        self.redirect('/')

class CurrentReading(webapp.RequestHandler):
    def post(self):
        # logging.info('Start of CurrentReading.post')
        data = self.request.get('content')
        obj = json.loads(data)
        mac = obj[u'mac']
        if device_exist(mac):
            readings = db.GqlQuery("SELECT * FROM LastReading WHERE mac = :1 LIMIT 1", mac)
            if readings.count(1) == 0:
                reading = LastReading()
            else:
                reading = readings.get()
            reading.content = data
            reading.mac = mac
            reading.put()

    def get(self):
        mac = self.request.get('mac')
        readings = db.GqlQuery("SELECT * FROM LastReading WHERE mac = :1 LIMIT 1", mac)
        if readings.count(1) == 0:
            response = '"no value"'
        else:
            response = readings.get().content
        self.response.headers['Content-Type'] = 'application/json'       
        # self.response.headers['Content-Type'] = 'text/plain'       
        self.response.out.write(response)

class ArchiveHandler(webapp.RequestHandler):
    def post(self):
        data = self.request.get('content')
        obj = json.loads(data)
        mac = obj[u'mac']
        now = datetime.datetime.now()
        if device_exist(mac):
            watts = obj[u'watts']
            for i in range(len(watts)):
                reading = Reading()
                reading.mac = mac
                reading.variable = '%.3d' % i
                # reading.timestamp = obj[u'datetime']
                reading.timestamp = now
                reading.timespan = 'r' # 'r' -> raw
                reading.value = watts[i]
                reading.put() 


class NewCommandHandler(webapp.RequestHandler):
    def post(self):
        """ Take the data from the command form and put it in the database """
        user = users.get_current_user()
        if (not user) or (not user_exist(user.email())):        
            self.redirect(users.create_login_url(self.request.uri))
        command = Command()
        command.mac = self.request.get('mac')
        command_obj = { 'mac':     self.request.get('mac'),
                        'type':    self.request.get('type'),
                        'shell':   self.request.get('shell'),
                        'timeout': self.request.get('timeout'),
                        'path':    self.request.get('path'),
                        'file':    self.request.get('file'),
                        'text':    self.request.get('text'),
                      }
        response_obj = { 'result':    'none',
                         'timestamp': time.ctime(),
                        }
        command.command = json.dumps(command_obj)
        command.complete = False
        command.response = json.dumps(response_obj)
        command.put()
        self.redirect('/recentcommands')

    def get(self):
        """ Present a page with a command form """
        user = users.get_current_user()
        if (not user) or (not user_exist(user.email())):        
            # self.redirect('/')
            self.redirect(users.create_login_url(self.request.uri))
        response = """<html>
<head>
<title>Post new command</title>
</head>
<body>
    <h1>Post new command</h1>
    <a href="/recentcommands">Recent commands</a>
    <form action="/newcommand" enctype="multipart/form-data" method="post">
      <table>
      <tr><td>mac:</td><td><input type="text" name="mac"></td></tr>
      <tr><td>type:</td><td><input type="text" name="type"></td></tr>
      <tr><td>shell</td><td><input type="text" name="shell"></td></tr>
      <tr><td>timeout</td><td><input type="text" name="timeout"></td></tr>
      <tr><td>path</td><td><input type="text" name="path"></td></tr>

      <tr><td>file</td><td><input type="file" name="file" size="40"></td></tr>
      <tr><td>text</td><td><textarea name="text" rows="3" cols="60"></textarea></td></tr>
      <tr><td></td><td></td></tr>
      </table>
      <div><input type="submit" value="Submit"></div>
    </form>
</body>
"""
        self.response.out.write(response)

class OutstandingHandler(webapp.RequestHandler):
    def get(self):
        """ Given a mac id, return all out outstanding commands for that mac"""
        command_objects = []
        mac = self.request.get('mac')
        if not device_exist(mac):
            response = '{"error":"mac"}'
        else:
            command_query = Command.all()
            command_query.filter('mac =', mac)
            command_query.filter('complete =', False)
            commands = command_query.fetch(10)
            for command in commands:
                command_obj = json.loads(command.command)
                command_obj['key'] = str(command.key())
                command_objects.append(command_obj)
            self.response.headers['Content-Type'] = 'application/json'       
            # self.response.headers['Content-Type'] = 'text/plain'
            response = json.dumps(command_objects)
        self.response.out.write(response)

class RecentCommandHandler(webapp.RequestHandler):
    def get(self):
        user = users.get_current_user()
        if (not user) or (not user_exist(user.email())):        
            self.redirect(users.create_login_url(self.request.uri))
        commands_query = Command.all().order('-date')
        commands = commands_query.fetch(20)
        data = []
        for command in commands:
            command_data = json.loads(command.command)
            result_data = json.loads(command.response)
            data.append({'command': command_data['shell'],
                         'mac': command_data['mac'],
                         'timestamp': result_data['timestamp'],
                         #'timestamp': 'timestamp',
                         'response': result_data['result']})
        template_values = {
            'commands': data,
            }

        path = os.path.join(os.path.dirname(__file__), 'recent.html')
        self.response.out.write(template.render(path, template_values))
        
class ResponseHandler(webapp.RequestHandler):
    def post(self):
        """ When the client executes a command it posts a response with the command key. """
        result_json = self.request.get('content')
        logging.info(result_json)
        result = json.loads(result_json)
        command_record = db.get(db.Key(result['key']))
        command_record.response = result_json
        command_record.complete = True
        command_record.put()
        
class UtilityHandler(webapp.RequestHandler):
    def get(self):
        """ A place to stash code, for instance, to create a first record. """
        response = '<pre>\nutility\n'
        user = users.get_current_user()
        if user:
            id = user.user_id()
            response += 'logged in as ' + user.nickname() + ' ' +user.email() + ' ' + id + '\n'
            #if id in ('142242157148121481368','107476162302531737134'):
            if user.email() in ('mshook@gmail.com'):
                response += 'Authorized\n'
                response += 'Performing utility\n'
                # Put utility code here

                old_utility_code = """
                device = Device()
                # device.mac = '00:d0:69:42:a2:0b'
                device.put()
                response += str(device_exist('foo'))
                response += str(device_exist('00:d0:69:42:a2:0b'))
                """

                user_record = User()
                user_record.email = 'foobar'
                user_record.put()
                
                # end of utility code
            else:
                response += 'Not authorized\n'
        else:
            response += 'not logged in\n'
        response += '</pre>\n'
        self.response.out.write(response)

def device_exist(mac):
    query = Device.all()
    query.filter('mac =', mac)
    return query.count(1) == 1

def user_exist(email):
    logging.info(email)
    query = User.all()
    query.filter('email =', email)
    return query.count(1) == 1
   

application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                      ('/sign', Guestbook),
                                      ('/last', CurrentReading),
                                      ('/archive', ArchiveHandler),
                                      ('/newcommand', NewCommandHandler),
                                      ('/recentcommands',RecentCommandHandler),
                                      ('/outstanding', OutstandingHandler),
                                      ('/response', ResponseHandler),
                                      ('/utility', UtilityHandler)],
                                     debug=True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()
